/***********************************************************************************
Copy right:	    hqyj Tech.
Author:         jiaoyue
Date:           2023.07.01
Description:    http请求处理
***********************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <stdio.h>
#include <modbus.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/msg.h>
#include "custom_handle.h"
#include "shmem.h"
#include "cJSON.h"
#include "msg_queue_peer.h"

#define KB 1024
#define HTML_SIZE (64 * KB)

//普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"

struct msgbuf
{
    long type; //必须用long，表示消息的类型，值>0
    //正文随便定义
    int num;
    char ch;
};

union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

struct msg //消息队列的消息类型
{
    long type;       //类型 modbus
    int key;         //key 值
    union val_t val; //数据（共用体类型）
};
struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};
static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username=");
    uname += strlen("username=");
    char *p = strstr(input, "password");
    *(p - 1) = '\0';
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password=");
    printf("passwd = %s\n", passwd);

    if (strcmp(uname, "admin") == 0 && strcmp(passwd, "admin") == 0)
    {
        sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname);
        strcat(reply_buf, "<script>window.location.href = '/index.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }
    else
    {
        printf("web login failed\n");

        //"用户名或密码错误"提示，chrome浏览器直接输送utf-8字符流乱码，没有找到太好解决方案，先过渡
        char out[128] = {0xd3, 0xc3, 0xbb, 0xa7, 0xc3, 0xfb, 0xbb, 0xf2, 0xc3, 0xdc, 0xc2, 0xeb, 0xb4, 0xed, 0xce, 0xf3};
        sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);
        strcat(reply_buf, "<script>window.location.href = '/login.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }

    return 0;
}

static int handle_cai(int sock, const char *input)
{
    key_t key;
    int shmid;
    char *p;
    char reply_buf[HTML_SIZE] = {0};

    //创建key值
    key = ftok("shm.c", 'd');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key: %#x\n", key);

    //创建或打开共享内存
    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666); //没有则创建共享内存，已有则返回-1

    if (shmid <= 0)
    {
        if (errno == EEXIST)                //如果已存在则直接打开共享内存
            shmid = shmget(key, 128, 0666); //直接打开共享内存，返回共享内存id
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid: %d\n", shmid);

    //映射共享内存到用户空间
    p = (char *)shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("shmat err");
        return -1;
    }
    printf("温度:%d\n", p[0]);
    printf("湿度:%d\n", p[1]);

    sprintf(reply_buf, "temp:%d humi:%d", p[0], p[1]);
    printf("resp = %s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);

    return 0;
}
static int handle_air(int sock, const char *input)
{
    key_t key;
    int msgid;
    key = ftok("msgid.c", 9);
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%#x\n", key);

    //打开消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid: %d\n", msgid);

    int number1;
    //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"air=%d\"", &number1);

    char reply_buf[HTML_SIZE] = {0};
    char buf1[128];
    sprintf(reply_buf, "a%d", number1);
    printf("resp = %s\n", reply_buf);
    if (strcmp(reply_buf, "a0") == 0)
    {
        printf("空调关闭\n");
        strcpy(buf1, "空调关闭\n");
    }
    else if (strcmp(reply_buf, "a1") == 0)
    {
        printf("空调打开\n");
        strcpy(buf1, "空调打开\n");
    }

    //添加消息
    struct msgbuf msg;
    msg.type = 20;
    msg.num = 0;
    strcpy(&msg.ch, reply_buf);
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0);

    send(sock, buf1, strlen(buf1), 0);

    return 0;
}

static int handle_fan(int sock, const char *input)
{
    key_t key;
    int msgid;
    key = ftok("msgid.c", 9);
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%#x\n", key);

    //打开消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid: %d\n", msgid);

    int number1;
    //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"fan=%d\"", &number1);

    char reply_buf[HTML_SIZE] = {0};
    char buf1[128];
    sprintf(reply_buf, "f%d", number1);
    printf("resp = %s\n", reply_buf);
    if (strcmp(reply_buf, "f0") == 0)
    {
        printf("风扇关闭\n");
        strcpy(buf1, "风扇关闭\n");
    }
    else if (strcmp(reply_buf, "f1") == 0)
    {
        printf("风扇打开\n");
        strcpy(buf1, "风扇打开\n");
    }
    //添加消息
    struct msgbuf msg;
    msg.type = 20;
    msg.num = 0;
    strcpy(&msg.ch, reply_buf);
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0);

    send(sock, buf1, strlen(buf1), 0);

    return 0;
}
static int handle_bee(int sock, const char *input)
{
    key_t key;
    int msgid;
    key = ftok("msgid.c", 9);
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%#x\n", key);

    //打开消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid: %d\n", msgid);

    int number1;
    //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"bee=%d\"", &number1);

    char reply_buf[HTML_SIZE] = {0};
    char buf1[128];
    sprintf(reply_buf, "b%d", number1);
    printf("resp = %s\n", reply_buf);
    if (strcmp(reply_buf, "b0") == 0)
    {
        printf("峰鸣器关闭\n");
        strcpy(buf1, "峰鸣器关闭\n");
    }
    else if (strcmp(reply_buf, "b1") == 0)
    {
        printf("峰鸣器打开\n");
        strcpy(buf1, "峰鸣器打开\n");
    }
    //添加消息
    struct msgbuf msg;
    msg.type = 20;
    msg.num = 0;
    strcpy(&msg.ch, reply_buf);
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0);

    send(sock, buf1, strlen(buf1), 0);

    return 0;
}

static int handle_led(int sock, const char *input)
{
    key_t key;
    int msgid;
    key = ftok("msgid.c", 9);
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%#x\n", key);

    //打开消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid: %d\n", msgid);

    int number1;
    //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"led=%d\"", &number1);

    char reply_buf[HTML_SIZE] = {0};
    char buf1[128];
    sprintf(reply_buf, "l%d", number1);
    printf("resp = %s\n", reply_buf);
    if (strcmp(reply_buf, "l0") == 0)
    {
        printf("led灯关闭\n");
        strcpy(buf1, "led灯关闭\n");
    }
    else if (strcmp(reply_buf, "l1") == 0)
    {
        printf("led灯打开\n");
        strcpy(buf1, "led灯打开\n");
    }
    //添加消息
    struct msgbuf msg;
    msg.type = 20;
    msg.num = 0;
    strcpy(&msg.ch, reply_buf);
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0);

    send(sock, buf1, strlen(buf1), 0);

    return 0;
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    //query_string不一定能用的到

    //先处理登录操作
    if (strstr(input, "username=") && strstr(input, "password="))
    {
        return handle_login(sock, input);
    }

    else if (strstr(input, "air="))
    {
        return handle_air(sock, input);
    }
    else if (strstr(input, "fan="))
    {
        return handle_fan(sock, input);
    }
    else if (strstr(input, "bee="))
    {
        return handle_bee(sock, input);
    }
    else if (strstr(input, "led="))
    {
        return handle_led(sock, input);
    }

    else if (strstr(input, "caijixinxi"))
    {
        return handle_cai(sock, input);
    }
    else //剩下的都是json请求，这个和协议有关了
    {
        // 构建要回复的JSON数据

        cJSON *root = cJSON_Parse(input);
        cJSON *item = cJSON_GetObjectItem(root, "type");
        cJSON *item1 = cJSON_GetObjectItem(root, "data");
        cJSON *data = cJSON_GetObjectItem(item1, "name");
        item = cJSON_GetObjectItem(item, "val");
        struct msg msg1;
        if (item->valueint == 1)
        {
            if (data->valuestring == "air")   //空调
            {
                msg1.key=104;
                msg1.type=1;
                msg1.val.b_val=item->valueint;
            }
            if (data->valuestring == "fan")   //风扇
            {
                msg1.key=105;
                msg1.type=1;
                msg1.val.b_val=item->valueint;
            }
            if (data->valuestring == "deng")      //灯
            {
                msg1.key=106;
                msg1.type=1;
                msg1.val.b_val=item->valueint;
            }
            
        }
         msg_queue_send("write", &msg1, sizeof(struct msg), 0);


        // 发送HTTP响应给客户端
    }

    return 0;
}